﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

using LINQToolKit;
using LINQToolKit.Collections;

namespace LINQToolKit.Douban
{
    internal sealed class DoubanQuerySession<T> : QuerySession<T>
    {
        private const string StartIndexPattern = @"start-index=\d+&?";
        private const string MaxResultsPattern = @"max-results=\d+&?";
        private const string QueryString = "{0}start-index={1}&max-results={2}&session=true";

        private IEntityProvider _provider;
        private int _totalResults;
        private int _itemsPerPage;
        private string _source;
        private bool _completedFlag;
        private int _nextStartIndex;

        public DoubanQuerySession(
            IEntityProvider provider, string source, int totalResults, int itemsPerPage)
            : this(provider, null, source, totalResults, itemsPerPage)
        {}

        public DoubanQuerySession(
            IEntityProvider provider, IEnumerable<T> inner, string source, int totalResults, int itemsPerPage)
            : base(inner)
        {
            provider.AssertNull("provider");
            source.AssertNull("source");
            
            this._provider = provider;
            this._source = source.IndexOf('?') > 0 ? source + "&" : source + "?";
            this._totalResults = totalResults;
            this._itemsPerPage = itemsPerPage;
            this._completedFlag = (totalResults == this.Inner.Count);
            this._nextStartIndex = this.Inner.Count + 1;
        }

        public int Count()
        {
            return this.IsCompleted ? this.Inner.Count : this._totalResults;
        }

        protected override IEnumerable<T> LoadData()
        {
            string queryUrl = this.BuildQueryUrl(this._source);
            this._nextStartIndex += this._itemsPerPage + 1;
            var result = (IEnumerable<T>)this._provider.Select(typeof(T), new Uri(queryUrl));

            if (result == null || result.Count() == 0 || 
                this._totalResults < this._nextStartIndex)
            {
                this._completedFlag = true;
            }

            return result;
        }

        private string BuildQueryUrl(string source)
        {
            var queryUrl = source;

            if (Regex.Match(queryUrl, StartIndexPattern).Success)
            {
                queryUrl = Regex.Replace(queryUrl, StartIndexPattern, string.Empty);
            }

            if (Regex.Match(queryUrl, MaxResultsPattern).Success)
            {
                queryUrl = Regex.Replace(queryUrl, MaxResultsPattern, string.Empty);
            }

            return string.Format(
                QueryString, queryUrl, this._nextStartIndex, this._nextStartIndex + this._itemsPerPage); ;
        }

        public override bool IsCompleted
        {
            get { return this._completedFlag; }
        }
    }
}
